home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gnumake
/
make360.zoo
/
job.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-11
|
35KB
|
1,493 lines
/* Job execution and handling for GNU Make.
Copyright (C) 1988-1991 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU Make is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
#include "commands.h"
#include "job.h"
#include "file.h"
#include "variable.h"
#include <errno.h>
/* Default path to search for executables. */
#ifdef atarist
static char default_path[] = ";/bin";
#else
static char default_path[] = ":/bin:/usr/bin";
#endif
/* Default shell to use. */
char default_shell[] = "/bin/sh";
extern int errno;
#if defined(USG) && !defined(HAVE_VFORK)
#define vfork fork
#define VFORK_NAME "fork"
#else /* Have vfork or not USG. */
#define VFORK_NAME "vfork"
#endif /* USG and don't have vfork. */
extern int vfork ();
#ifdef _POSIX_SOURCE
#include <sys/wait.h>
#define WAIT_NOHANG(status) waitpid(-1, (status), WNOHANG)
#else /* Not _POSIX_SOURCE. */
#if defined(HAVE_SYS_WAIT) || !defined(USG)
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifndef wait3
extern int wait3 ();
#endif
#define WAIT_NOHANG(status) wait3((status), WNOHANG, (struct rusage *) 0)
#ifndef wait
extern int wait ();
#endif
#endif /* HAVE_SYS_WAIT || !USG */
#endif /* _POSIX_SOURCE. */
#if defined(WTERMSIG) || (defined(USG) && !defined(HAVE_SYS_WAIT))
#define WAIT_T int
#ifndef WTERMSIG
#define WTERMSIG(x) ((x) & 0x7f)
#endif
#ifndef WCOREDUMP
#define WCOREDUMP(x) ((x) & 0x80)
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(x) (((x) >> 8) & 0xff)
#endif
#ifndef WIFSIGNALED
#define WIFSIGNALED(x) (WTERMSIG (x) != 0)
#endif
#ifndef WIFEXITED
#define WIFEXITED(x) (WTERMSIG (x) == 0)
#endif
#else /* WTERMSIG not defined and have <sys/wait.h> or not USG. */
#ifdef atarist
# define WAIT_T int
# define WTERMSIG(x) 0
# define WCOREDUMP(x) 0
# define WEXITSTATUS(x) x
# define WIFSIGNALED(x) (WTERMSIG (x) != 0)
# define WIFEXITED(x) (WTERMSIG (x) == 0)
# undef WAIT_NOHANG
#else
#define WAIT_T union wait
#define WTERMSIG(x) ((x).w_termsig)
#define WCOREDUMP(x) ((x).w_coredump)
#define WEXITSTATUS(x) ((x).w_retcode)
#endif /* atarist */
#ifndef WIFSIGNALED
#define WIFSIGNALED(x) (WTERMSIG(x) != 0)
#endif
#ifndef WIFEXITED
#define WIFEXITED(x) (WTERMSIG(x) == 0)
#endif
#endif /* WTERMSIG defined or USG and don't have <sys/wait.h>. */
#if defined(__GNU_LIBRARY__) || defined(_POSIX_SOURCE)
#include <sys/types.h>
#define GID_T gid_t
#ifdef hpux
#include <sys/param.h>
#define getdtablesize() NOFILE
#endif
#else /* Not GNU C library. */
#define GID_T int
extern int dup2 ();
extern int fork (), execve ();
extern void _exit ();
extern int geteuid (), getegid ();
extern int setgid (), getgid ();
#ifndef USG
extern int getdtablesize ();
#else
#include <sys/param.h>
#define getdtablesize() NOFILE
#endif
#endif /* GNU C library. */
extern void wait_to_start_job ();
extern int start_remote_job_p ();
extern int start_remote_job (), remote_status ();
#if (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
static char *sys_siglist[NSIG];
void init_siglist ();
#else /* Not (USG and HAVE_SIGLIST), or DGUX. */
extern char *sys_siglist[];
#endif /* USG and not HAVE_SIGLIST, or DGUX. */
int child_handler ();
static void free_child (), start_job ();
/* Chain of all children. */
struct child *children = 0;
/* Number of children currently running. */
unsigned int job_slots_used = 0;
/* Nonzero if the `good' standard input is in use. */
static int good_stdin_used = 0;
/* Write an error message describing the exit status given in
EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
Append "(ignored)" if IGNORED is nonzero. */
static void
child_error (target_name, exit_code, exit_sig, coredump, ignored)
char *target_name;
int exit_code, exit_sig, coredump;
int ignored;
{
char *ignore_string = ignored ? " (ignored)" : "";
if (exit_sig == 0)
error ("*** [%s] Error %d%s", target_name, exit_code, ignore_string);
else
{
char *coredump_string = coredump ? " (core dumped)" : "";
if (exit_sig > 0 && exit_sig < NSIG)
error ("*** [%s] %s%s",
target_name, sys_siglist[exit_sig], coredump_string);
else
error ("*** [%s] Signal %d%s", target_name, exit_sig, coredump_string);
}
}
extern void block_remote_children (), unblock_remote_children ();
extern int fatal_signal_mask;
#ifdef USG
/* Set nonzero in the interval when it's possible that we may see a dead
child that's not in the `children' chain. */
static int unknown_children_possible = 0;
#endif
/* Block the child termination signal and fatal signals. */
static void
block_signals ()
{
#ifdef USG
/* Tell child_handler that it might see children that aren't yet
in the `children' chain. */
unknown_children_possible = 1;
/* Ignoring SIGCLD makes wait always return -1.
Using the default action does the right thing. */
(void) SIGNAL (SIGCLD, SIG_DFL);
#else /* Not USG. */
/* Block the signals. */
#ifndef atarist
(void) sigblock (fatal_signal_mask | sigmask (SIGCHLD));
#endif /* atarist */
#endif
block_remote_children ();
}
/* Unblock the child termination signal and fatal signals. */
static void
unblock_signals ()
{
#ifdef USG
(void) SIGNAL (SIGCLD, child_handler);
/* It should no longer be possible for children not in the chain to die. */
unknown_children_possible = 0;
#else /* Not USG. */
/* Unblock the signals. */
#ifndef atarist
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask | sigmask (SIGCHLD)));
#endif
#endif
unblock_remote_children ();
}
static char *signals_blocked_p_stack = 0;
static unsigned int signals_blocked_p_max;
static unsigned int signals_blocked_p_depth;
/* Make signals blocked in FLAG is nonzero, unblocked if FLAG is zero.
Push this setting on the signals_blocked_p_stack, so it can be
popped off by pop_signals_blocked_p. */
void
push_signals_blocked_p (flag)
int flag;
{
int blocked;
if (signals_blocked_p_stack == 0)
{
signals_blocked_p_max = 8;
signals_blocked_p_stack = (char *) xmalloc (8);
signals_blocked_p_depth = 1;
signals_blocked_p_stack[0] = flag;
blocked = 0;
}
else
{
if (signals_blocked_p_depth == signals_blocked_p_max)
{
signals_blocked_p_max += 8;
signals_blocked_p_stack
= (char *) xrealloc(signals_blocked_p_stack,
signals_blocked_p_max);
}
blocked = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth - 1]);
signals_blocked_p_stack[++signals_blocked_p_depth - 1] = flag;
}
if (blocked && !flag)
unblock_signals ();
else if (flag && !blocked)
block_signals ();
}
/* Pop the signals_blocked_p setting from the stack
and block or unblock signals as appropriate. */
void
pop_signals_blocked_p ()
{
int blocked, block;
blocked = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth-- - 1]);
block = (signals_blocked_p_depth > 0
&& signals_blocked_p_stack[signals_blocked_p_depth - 1]);
if (block && !blocked)
block_signals ();
else if (blocked && !block)
unblock_signals ();
}
extern int shell_function_pid, shell_function_completed;
/* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
storing the returned status and the new command state (`cs_finished')
in the `file' member of the `struct child' for the dead child,
and removing the child from the chain.
If we were called as a signal handler, SIG should be SIGCHLD
(SIGCLD for USG). If instead it is zero, we were called explic